import math


def haversine(lon1, lat1, lon2, lat2):
    """
    计算两点之间的球面距离（单位：米）
    :param lon1: 点1经度
    :param lat1: 点1纬度
    :param lon2: 点2经度
    :param lat2: 点2纬度
    :return: 距离（单位：米）
    """
    # 将经纬度从度转换为弧度
    lon1, lat1, lon2, lat2 = map(math.radians, [lon1, lat1, lon2, lat2])

    # Haversine公式
    dlon = lon2 - lon1
    dlat = lat2 - lat1
    a = math.sin(dlat / 2) ** 2 + math.cos(lat1) * math.cos(lat2) * math.sin(dlon / 2) ** 2
    c = 2 * math.atan2(math.sqrt(a), math.sqrt(1 - a))

    # 地球半径（单位：米）
    R = 6371000
    distance_meters = R * c
    return distance_meters


def calculate_catch_up_time(
        v_A0,  # 车辆A的初始速度 (m/s)
        v_B,  # 车辆B的速度 (恒定, m/s)
        a_A,  # 车辆A的加速度 (m/s²)
        n,  # 车辆A提速百分比 (%)
        lon_A, lat_A,  # 车辆A的经纬度
        lon_B, lat_B  # 车辆B的经纬度
):
    """
    计算车辆A提速后追上车辆B的时间。

    返回:
        (加速时间, 匀速时间):
            - 如果在加速阶段追上，匀速时间为0。
            - 如果在匀速阶段追上，返回实际的匀速时间。
            - 如果无法追上，匀速时间为None。
    """
    # 参数验证
    if a_A <= 0:
        raise ValueError("加速度必须为正数")
    if n <= 0:
        raise ValueError("提速百分比必须为正数")

    # 计算初始距离
    D0 = haversine(lon_A, lat_A, lon_B, lat_B)

    # 1. 计算提速后速度
    v_A1 = v_A0 * (1 + n / 100)

    # 2. 计算加速时间
    t_acc = (v_A1 - v_A0) / a_A

    # 3. 计算加速阶段行驶距离（A车）
    D_acc_A = v_A0 * t_acc + 0.5 * a_A * t_acc ** 2

    # 4. 计算加速阶段B车行驶距离
    D_acc_B = v_B * t_acc

    # 5. 计算加速结束时两车的距离
    D_after_acc = D0 + D_acc_B - D_acc_A

    # 检查是否在加速阶段追上
    # 解方程: 0.5*a_A*t^2 + (v_A0 - v_B)*t - D0 = 0
    a = 0.5 * a_A
    b = v_A0 - v_B
    c = -D0
    discriminant = b ** 2 - 4 * a * c

    if discriminant >= 0:
        sqrt_discriminant = math.sqrt(discriminant)
        t1 = (-b + sqrt_discriminant) / (2 * a)
        t2 = (-b - sqrt_discriminant) / (2 * a)
        valid_times = [t for t in [t1, t2] if 0 <= t <= t_acc]
        # 在加速阶段追上
        if valid_times:
            t_catch = min(valid_times)
            return (t_catch, 0)

            # 检查是否在匀速阶段追上
    # 在匀速阶段追上
    if v_A1 > v_B and D_after_acc > 0:
        t_const = D_after_acc / (v_A1 - v_B)
        return (t_acc, t_const)

        # 无法追上
    return (t_acc, None)


def calculate_catch_down_time(
        v_A0,  # 车辆A的初始速度 (m/s)
        v_B,  # 车辆B的速度 (恒定, m/s)
        a_A,  # 车辆A的减速度 (m/s², 正值)
        n,  # 车辆A减速百分比 (%)
        lon_A, lat_A,  # 车辆A的经纬度
        lon_B, lat_B  # 车辆B的经纬度
):
    """
    计算车辆B追上减速的车辆A的时间。

    返回:
        (减速时间, 匀速时间):
            - 如果在减速阶段追上，匀速时间为0。
            - 如果在匀速阶段追上，返回实际的匀速时间。
            - 如果无法追上，匀速时间为None。
    """
    # 计算初始距离
    D0 = haversine(lon_A, lat_A, lon_B, lat_B)

    # 车辆A减速后的速度
    v_A1 = v_A0 * (1 - n / 100)

    # 减速时间
    t_dec = (v_A1 - v_A0) / (-a_A)

    # 减速阶段行驶距离
    D_dec = v_A0 * t_dec + 0.5 * (-a_A) * t_dec ** 2

    # 检查是否在减速阶段追上
    # 解方程: 0.5*(-a_A)*t^2 + (v_A0 - v_B)*t - D0 = 0
    a = 0.5 * (-a_A)
    b = v_A0 - v_B
    c = -D0
    discriminant = b ** 2 - 4 * a * c

    if discriminant >= 0:
        sqrt_discriminant = math.sqrt(discriminant)
        t1 = (-b + sqrt_discriminant) / (2 * a)
        t2 = (-b - sqrt_discriminant) / (2 * a)
        valid_times = [t for t in [t1, t2] if 0 <= t <= t_dec]

        if valid_times:
            t_catch = min(valid_times)
            return (t_catch, 0)  # 在减速阶段追上

    # 检查是否在匀速阶段追上
    if v_A1 < v_B:
        t_const = (D0 + v_A1 * t_dec - D_dec) / (v_B - v_A1)
        if t_const > t_dec:
            return (t_dec, t_const)  # 在匀速阶段追上

    # 无法追上
    return (t_dec, None)
